package testcase;

import static org.junit.Assert.*;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.lang.reflect.Method;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import ui.UI;
import dataobj.ConfigTO;
import MainComponent.MainFunction;
import MainComponent.TimetableCreator;

public class TestMainFunction {

	private static ByteArrayOutputStream outContent = new ByteArrayOutputStream();
	private static ByteArrayInputStream inContent;
	
	@Before
	public void setUp(){
		System.setOut(new PrintStream(outContent));
	}
	
	@After
	public void cleanUp(){
		outContent.reset();
		System.setOut(System.out);
		System.setIn(System.in);
	}
	
	private void setInContent(String s){
		inContent = new ByteArrayInputStream(s.getBytes());
		System.setIn(inContent);
	}
	
	//Test Getuniversity method 
	//with ConfigTO stub
	@Test
	public void testGetUniversity1() throws Exception {
		class ConfigTOStub extends ConfigTO{
			public boolean setUniversity(String s){return true;}
		}
		setInContent("cityu");
		Method method = MainFunction.class.getDeclaredMethod("getUniversity", ConfigTO.class, UI.class);
		method.setAccessible(true);
		assertEquals(method.invoke(new MainFunction(), new ConfigTOStub(), new UI()), true);
		assertEquals("Please enter the university you are in (cityu, polyu, hku, bu, ou, cu)\n", outContent.toString());
	}
	
	//with ConfigTO stub
	@Test
	public void testGetUniversity2() throws Exception {
		class ConfigTOStub extends ConfigTO{
			public boolean setUniversity(String s){return false;}
		}
		setInContent("cityu");
		Method method = MainFunction.class.getDeclaredMethod("getUniversity", ConfigTO.class, UI.class);
		method.setAccessible(true);
		assertEquals(method.invoke(new MainFunction(), new ConfigTOStub(), new UI()), false);
		assertEquals("Please enter the university you are in (cityu, polyu, hku, bu, ou, cu)\nNo such univeristy exists, please try again\n", outContent.toString());
	}
	
	//without stub and with correct input
	@Test
	public void testGetUniversity3() throws Exception {
		setInContent("cityu");
		Method method = MainFunction.class.getDeclaredMethod("getUniversity", ConfigTO.class, UI.class);
		method.setAccessible(true);
		assertEquals(method.invoke(new MainFunction(), new ConfigTO(), new UI()), true);
		assertEquals("Please enter the university you are in (cityu, polyu, hku, bu, ou, cu)\n", outContent.toString());
	}
	
	//without stub and with incorrect input
	@Test
	public void testGetUniversity4() throws Exception {
		setInContent("abcd");
		Method method = MainFunction.class.getDeclaredMethod("getUniversity", ConfigTO.class, UI.class);
		method.setAccessible(true);
		assertEquals(method.invoke(new MainFunction(), new ConfigTO(), new UI()), false);
		assertEquals("Please enter the university you are in (cityu, polyu, hku, bu, ou, cu)\nNo such univeristy exists, please try again\n", outContent.toString());
	}
	
	//Test createTimetable
	@Test
	public void testCreateTimeTable1() throws Exception{
		class creatorStub extends TimetableCreator{
			public creatorStub(ConfigTO config) {
				super(config);
			}
			
			public boolean createTimeTable(){
				return true;
			}
		}
		Method method = MainFunction.class.getDeclaredMethod("createTimetable", UI.class, TimetableCreator.class);
		method.setAccessible(true);
		assertEquals(method.invoke(new MainFunction(), new UI(), new creatorStub(new ConfigTO())), true);
	}
	
	//Test createTimetable
	@Test
	public void testCreateTimeTable2() throws Exception{
		class creatorStub extends TimetableCreator{
			public creatorStub(ConfigTO config) {
				super(config);
			}
			
			public boolean createTimeTable(){
				return false;
			}
		}
		Method method = MainFunction.class.getDeclaredMethod("createTimetable", UI.class, TimetableCreator.class);
		method.setAccessible(true);
		assertEquals(method.invoke(new MainFunction(), new UI(), new creatorStub(new ConfigTO())), false);
	}

}
